package com.oliet.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Maps;
import com.oliet.common.dto.role.CreateRoleDTO;
import com.oliet.common.dto.role.UpdateRoleDTO;
import com.oliet.common.vo.page.PageVO;
import com.oliet.common.vo.permission.PermissionVO;
import com.oliet.common.vo.role.RoleVO;
import com.oliet.entity.Permissions;
import com.oliet.entity.RolePermissions;
import com.oliet.entity.Roles;
import com.oliet.entity.UserRoles;
import com.oliet.entity.base.BaseEntity;
import com.oliet.exception.CustomException;
import com.oliet.exception.ErrorEnum;
import com.oliet.mapper.PermissionsMapper;
import com.oliet.mapper.RolesMapper;
import com.oliet.mapper.UserRolesMapper;
import com.oliet.service.RolePermissionsService;
import com.oliet.service.RolesService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author JZP
 * @since 2023-11-26
 */
@Service
public class RolesServiceImpl extends ServiceImpl<RolesMapper, Roles> implements RolesService {

    @Autowired
    private RolePermissionsService rolePermissionsService;
    @Autowired
    private PermissionsMapper permissionsMapper;
    @Autowired
    private UserRolesMapper userRolesMapper;

    @Override
    public void create(CreateRoleDTO param) {
        //校验角色名称
        this.verifyRoleName(param.getRoleName());
        //创建角色，并赋值属性
        Roles po = new Roles();
        BeanUtil.copyProperties(param, po);
        //保存角色
        this.save(po);
        //保存角色权限
        this.rolePermissionsService.batchInsert(po.getId(), param.getPermissionIds());
    }

    @Override
    public void update(UpdateRoleDTO param) {
        //查询角色
        Roles po = this.getById(param.getId());
        Assert.notNull(po, () -> new CustomException(ErrorEnum.ROLE_DOES_NOT_EXIST));
        //校验角色名称
        Roles one = this.getOne(new LambdaQueryWrapper<Roles>().eq(Roles::getRoleName, param.getRoleName()));
        if (ObjectUtil.isNotNull(one) && !po.getId().equals(one.getId())) {
            throw new CustomException(ErrorEnum.ROLE_NAME_EXIST);
        }
        //修改角色数据
        BeanUtil.copyProperties(param, po, "id");
        this.updateById(po);
        //保存角色权限
        this.rolePermissionsService.deleteByRoleId(po.getId());
        List<Permissions> allList = this.permissionsMapper.selectList(null);
        List<Long> ids = this.completeParentIds(allList, param.getPermissionIds());
        this.rolePermissionsService.batchInsert(po.getId(), ids);
    }

    public static List<Long> completeParentIds(List<Permissions> allList, List<Long> ids) {
        if (CollectionUtil.isEmpty(ids)) {
            return ids;
        }
        Set<Long> completeIds = new HashSet<>(ids); // 使用 Set 避免重复
        for (Long id : ids) {
            completeIds.addAll(findParentIds(allList, id));
        }
        return new ArrayList<>(completeIds);
    }

    private static Set<Long> findParentIds(List<Permissions> allList, Long childId) {
        Set<Long> parentIds = new HashSet<>();
        Permissions childPermission = findById(allList, childId);
        if (childPermission != null) {
            parentIds.add(childPermission.getId()); // 将子级权限ID添加到结果中
            Long parentId = childPermission.getParentId();
            // 递归查找上级权限ID，直至顶级权限
            while (parentId != 0) {
                Permissions parentPermission = findById(allList, parentId);
                if (parentPermission != null) {
                    parentIds.add(parentPermission.getId());
                    parentId = parentPermission.getParentId();
                } else {
                    break; // 上级权限不存在，结束循环
                }
            }
        }
        return parentIds;
    }

    private static Permissions findById(List<Permissions> allList, Long id) {
        for (Permissions permission : allList) {
            if (permission.getId().equals(id)) {
                return permission;
            }
        }
        return null;
    }

    @Override
    public void verifyRoleName(String roleName) {
        if (StringUtils.isBlank(roleName)) {
            throw new CustomException(ErrorEnum.INVALID_PARAMETER);
        }
        long count = this.count(new LambdaQueryWrapper<Roles>().eq(Roles::getRoleName, roleName));
        if (count > 0) {
            throw new CustomException(ErrorEnum.ROLE_NAME_EXIST);
        }
    }

    @Override
    public PageVO<RoleVO> pageList(Long pageNo, Long pageSize, String search) {
        //分页查询
        Page<Roles> page = new Page<>(pageNo, pageSize);
        Page<Roles> poData = this.page(page, new LambdaQueryWrapper<Roles>()
                .and(
                        StrUtil.isNotBlank(search),
                        wrapper -> wrapper.like(Roles::getRoleName, search)
                                .or()
                                .like(Roles::getDescription, search)
                ).orderByDesc(BaseEntity::getDateCreated)
        );
        Map<Long, List<Long>> permissionIdMap = getPermissionIdMap(poData);
        List<RoleVO> voList = RoleVO.poListConverVoList(poData.getRecords(), permissionIdMap);
        PageVO<RoleVO> pageVo = new PageVO<>(poData.getCurrent(), poData.getSize(), poData.getTotal(), voList);
        return pageVo;
    }

    public Map<Long, List<Long>> getPermissionIdMap(Page<Roles> poData) {
        Map<Long, List<Long>> result = Maps.newHashMap();
        if (ObjectUtil.isNull(poData) || CollectionUtil.isEmpty(poData.getRecords())) {
            return result;
        }
        List<Long> ids = poData.getRecords().stream().map(BaseEntity::getId).collect(Collectors.toList());
        List<RolePermissions> rpList = this.rolePermissionsService.list(new LambdaQueryWrapper<RolePermissions>()
                .in(RolePermissions::getRoleId, ids));

        List<Permissions> allList = this.permissionsMapper.selectList(null);


        result = rpList.stream()
                .collect(Collectors.groupingBy(RolePermissions::getRoleId,
                        Collectors.mapping(RolePermissions::getPermissionId, Collectors.toList())));

        result.forEach((k, v) -> {
            List<Permissions> tempList = allList.stream().filter(p -> v.contains(p.getId())).collect(Collectors.toList());
            for (Permissions p : tempList) {
                if (v.contains(p.getParentId())) {
                    v.remove(p.getParentId());
                }
            }
        });


        return result;
    }

    @Override
    public RoleVO info(Long id) {
        Roles po = this.getById(id);
        Assert.notNull(po, () -> new CustomException(ErrorEnum.ROLE_DOES_NOT_EXIST));
        RoleVO vo = RoleVO.poConverVo(po);
        //获取角色权限
        List<PermissionVO> permissionVoList = this.rolePermissionsService.getPermissionVoByRoleId(po.getId());
        vo.setPermissionVoList(permissionVoList);
        return vo;
    }

    @Override
    public void deleteById(Long id) {
        //查询角色是否存在
        Roles po = this.getById(id);
        if (ObjectUtil.isNull(po)) {
            throw new CustomException(ErrorEnum.ROLE_DOES_NOT_EXIST);
        }
        //查看该角色是否被用户关联
        Long count = this.userRolesMapper.selectCount(new LambdaQueryWrapper<UserRoles>().eq(UserRoles::getRoleId, id));
        if (count > 0){
            throw new CustomException(ErrorEnum.ROLE_EXIST_USE);
        }
        //删除角色
        this.removeById(id);
        //查询角色权限关系表
        List<RolePermissions> rpList = this.rolePermissionsService.list(
                new LambdaQueryWrapper<RolePermissions>()
                        .eq(RolePermissions::getRoleId, id));
        if (CollectionUtil.isNotEmpty(rpList)) {
            this.rolePermissionsService.remove(new LambdaQueryWrapper<RolePermissions>()
                    .eq(RolePermissions::getRoleId, id));
        }

    }


}
